// -*- C++ -*-

#ifndef _DGINTMATRIX_
#define _DGINTMATRIX_

#include <map>
#include <iostream>
#include <cstdio>
using std::cerr;
#include <cstdlib>

#include <cstring>

/*! \brief row-major matrix for storing integer information \ingroup dgdatastructure */

class DGIntMatrix
{
private:

  size_t r,c;
  int   *data;

public:
  
  inline size_t size1() const {return r;}
  inline size_t size2() const {return c;}
  
  ~DGIntMatrix() {if (data) delete [] data;}
  DGIntMatrix():r(0),c(0),data(NULL){}
  DGIntMatrix(size_t R, size_t C):r(R),c(C),data(new int[r*c]) {setToZero();}
  DGIntMatrix(const DGIntMatrix& other):r(other.size1()),c(other.size2()),data(new int[r*c]) {
    std::memcpy(data,other.seeData(),r*c*sizeof(int));
  }
  
  void resize(size_t R,size_t C) {r=R;c=C; if (data) delete [] data; data = new int[r*c]; setToZero();}
  
  void setToZero() {if (data) for (size_t i=0;i<r*c;i++) data[i] = 0;}
  
  /*!\brief access to entry */
  inline       int& operator() (size_t i,size_t j)           {
#ifdef DEBUG_CHECK_BOUNDS
    if (data==NULL) {
      cerr << "Accessing entry " << i << "," << j << " in non-allocated integer matrix";
      exit(1);
    }
    if ((i >= r) || (j >= c)) {
      cerr << "Indices " << i << "," << j << " out of range (" << r << "x" << c << ")";
      exit(1);
    }
#endif
    return *(data + j + i*c);
  }
  
  /*!\brief constant access to entry */
  inline const int& operator() (size_t i,size_t j)     const {
#ifdef DEBUG_CHECK_BOUNDS
    if (data==NULL) {
      cerr << "Accessing entry " << i << "," << j << " in non-allocated integer matrix";
      exit(1);
    }
    if ((i >= r) || (j >= c)) {
      cerr << "Indices " << i << "," << j << " out of range (" << r << "x" << c << ")";
      exit(1);
    }
#endif
    return *(data + j + i*c);
  }
  
  /*!\brief access to row i */
  inline       int * operator [] (const size_t i)       {
#ifdef DEBUG_CHECK_BOUNDS
    if (data==NULL) {
      cerr << "Accessing row " << i << " in non-allocated integer matrix";
      exit(1);
    }
    if ((i >= r)) {
      cerr << "Row index " << " out of range (" << r << "x" << c << ")";
      exit(1);
    }
#endif
    return data + i*c;
  }
  
  /*!\brief constant access to row i */
  inline const int * operator [] (const size_t i) const {
#ifdef DEBUG_CHECK_BOUNDS
    if (data==NULL) {
      cerr << "Accessing row " << i << " in non-allocated integer matrix";
      exit(1);
    }
    if ((i >= r)) {

      cerr << "Row index " << " out of range (" << r << "x" << c << ")";
      exit(1);
    }
#endif
    return data + i*c;
  }  
  
  inline const int * seeData() const {return data;}

  void PRINT (const char *comment = "") const
  {
#ifdef DEBUG_CHECK_BOUNDS
    if (data==NULL) exit(1); 
#endif
    printf ("printing integer matrix %s\n",comment);
    size_t index = 0;
    for (size_t i = 0 ; i < r ; i++) {
      for (size_t j = 0 ; j < c ; j++,index++) {
        printf("%d ",data[index]);
      }
      printf("\n");
    }
    printf("\n");
  }
};

#endif
